package rest

import (
	"compress/flate"
	"compress/gzip"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"strings"

	"gitee.com/hexug/go-chain-restful-client/common/format"
	"gitee.com/hexug/go-chain-restful-client/negotiator"
	"github.com/andybalholm/brotli"
	"github.com/bytedance/sonic"
	"github.com/golang/snappy"
	"github.com/klauspost/compress/zstd"
)

func (r *Response) withBody(body io.ReadCloser) {
	r.body = body
}

func (r *Response) withHeader(headers http.Header) {
	r.headers = headers
}

func (r *Response) withStatusCode(code int) {
	r.statusCode = code
}
func (r *Response) withStatus(status string) {
	r.status = status
}
func (r *Response) withCookies(cookies []*http.Cookie) {
	r.cookies = cookies
}
func (r *Response) withUrl(url *url.URL) {
	r.url = url
}

func (r *Response) readBody() {
	r.lock.Lock()
	defer r.lock.Unlock()

	if r.body == nil || r.isRead {
		return
	}

	r.isRead = true
	defer r.body.Close()
	var bodyReader io.Reader
	switch HeaderFilterFlags(r.headers.Get(CONTENT_ENCODING_HEADER)) {
	case "gzip":
		dp, err := gzip.NewReader(r.body)
		if err != nil {
			r.err = err
			return
		}
		bodyReader = dp
	case "deflate":
		bodyReader = flate.NewReader(r.body)
	case "br":
		bodyReader = brotli.NewReader(r.body)
	case "zstd":
		dp, err := zstd.NewReader(r.body)
		if err != nil {
			r.err = err
			return
		}
		bodyReader = dp
	case "snappy":
		bodyReader = snappy.NewReader(r.body)
	default:
		bodyReader = r.body
	}
	// 读取数据
	body, err := io.ReadAll(bodyReader)
	if err != nil {
		r.err = err
		return
	}
	r.debug(body)

	r.bf = body
}

func (r *Response) debug(body []byte) {
	r.log.L().Debugf("状态码: %d", r.statusCode)
	r.log.L().Debugf("响应头:")
	for k, v := range r.headers {
		r.log.L().Debugf("\t%s=%s", k, strings.Join(v, ","))
	}
	var data interface{}
	err := sonic.Unmarshal(body, &data)
	if err == nil {
		r.log.L().Debugln("Body: ", format.FormatBytesToJsion(body))
	} else {
		r.log.L().Debugln("Body: ", string(body))
	}

}

// 链式获取header 通过传入一个header的key和接收的字符串指针，返回的对应value是在传入的字符串指针中
func (r *Response) Header(header string, v *string) *Response {
	*v = r.headers.Get(header)
	return r
}

// 不处理返回, 直接判断请求是否正常
func (r *Response) Error() error {
	r.readBody()
	if r.statusCode == 0 {
		return r.err
	}

	// 判断status code
	if r.statusCode/100 != 2 && r.statusCode/100 != 3 {
		r.err = fmt.Errorf("状态码是：%d, 非2xx或者3XX\n响应数据：%s", r.statusCode, string(r.bf))
		// r.log.L().Errorw("############################################")
		// r.log.L().Errorf("状态码是：%d, not 2xx或者3XX", r.statusCode)
		// r.log.L().Errorf("响应数据: %s", string(r.bf))
		// r.log.L().Errorw("############################################")
	}

	return r.err
}

// 请求正常的情况下, 获取返回的数据, 不做解析,以byte[]形式返回
func (r *Response) Raw() ([]byte, error) {
	if err := r.Error(); err != nil {
		return nil, err
	}
	return r.bf, r.err
}

// TODO待改进
func (r *Response) Into(v any) error {
	if err := r.Error(); err != nil {
		return err
	}
	if r.contentType == "" {
		r.contentType = HeaderFilterFlags(r.headers.Get(CONTENT_TYPE_HEADER))
	}

	nt := negotiator.GetNegotiator(r.contentType)
	return nt.Decode(r.bf, v)
}

// 获取相应状态码
func (r *Response) StatusCode() int {
	return r.statusCode
}

// 非链式获取header，直接返回header的key对应的value
func (r *Response) GetHeader(key string) string {
	return r.headers.Get(key)
}

// 获取所有的header
func (r *Response) Headers() http.Header {
	return r.headers
}

// 获取相应状态
func (r *Response) Status() string {
	return r.status
}

// 获取响应的cookie
func (r *Response) Cookies() []*http.Cookie {
	return r.cookies
}

// 获取响应的编码类型
func (r *Response) Encoding() string {
	return r.GetHeader("Content-Type")
}

// 获取文本格式的body
func (r *Response) Text() string {
	if err := r.Error(); err != nil {
		r.log.L().Errorln("获取文本格式的body异常：", err.Error())
		return ""
	}
	var data interface{}
	err := sonic.Unmarshal(r.bf, &data)
	if err == nil {
		return format.FormatBytesToJsion(r.bf)
	} else {
		return string(r.bf)
	}
}

// 获取URL
func (r *Response) Url() *url.URL {
	return r.url
}
